package com.tuinui.trade.manager;


import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.FetchOptions;

import com.google.appengine.api.memcache.ErrorHandlers;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.tuinui.trade.entry.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;
import java.util.logging.Level;

/**
 * Created with IntelliJ IDEA.
 * User: kaweepapkongkittisan
 * Date: 5/22/13
 * Time: 11:47 PM
 * To change this template use File | Settings | File Templates.
 */
public class DataManager extends EntityMapper{
    final public static Logger _log = LoggerFactory.getLogger(DataManager.class);

    private static DataManager instance;

    //private static EntityManagerFactory emfInstance = Persistence
    //        .createEntityManagerFactory("transactions-optional");

    private DataManager() {
    }

    public static DataManager getInstance(){
        if (instance == null) {
            instance = new DataManager();
        }
        return instance;
    }

    public void savePriceList(List<StockTradeDailyEntry> priceList)throws Exception{
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        List<Entity> entities = new ArrayList<Entity>();

        for(StockTradeDailyEntry price: priceList){
            Entity entity = convertStockPriceDailyEntryToEntity(price);

            entities.add(entity);

        }
        datastore.put(entities);

    }
    public void cleanPrice() {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Query query = new Query("Stock");
        List<Entity> entities = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
        List<Key> keys = new ArrayList<Key>();
        for(Entity entity: entities){

            keys.add(entity.getKey());

        }
        datastore.delete(keys);

    }
    public List<StockTradeDailyEntry> getPriceList() {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Query query = new Query("Stock");
        List<Entity> entities = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
        List<StockTradeDailyEntry> priceList = new ArrayList<StockTradeDailyEntry>();
        for(Entity entity: entities){
            StockTradeDailyEntry price = convertEntityToStockPriceDailyEntry(entity);
            priceList.add(price);

        }

        return priceList;
    }
    public List<TransactionEntry> getTransactionList(String owner) {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Query.Filter ownerFilter =
                new Query.FilterPredicate("owner",
                        Query.FilterOperator.EQUAL,
                        owner);
        Query query = new Query("Transaction")
                .addSort("date", Query.SortDirection.DESCENDING);
        query.setFilter(ownerFilter);
        List<Entity> entities = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
        List<TransactionEntry> transactionList = new ArrayList<TransactionEntry>();
        for(Entity entity: entities){
            TransactionEntry trx = convertEntityToTransactionEntry(entity);
            transactionList.add(trx);

        }


        return transactionList;
    }


    public Map<String, StockTradeDailyEntry> getPriceMap() {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Query query = new Query("Stock");
        List<Entity> entities = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
        Map<String, StockTradeDailyEntry> priceList = new LinkedHashMap<String, StockTradeDailyEntry>();
        for(Entity entity: entities){
            StockTradeDailyEntry price = convertEntityToStockPriceDailyEntry(entity);

            priceList.put(price.getSymbol(), price);
        }

        return priceList;
    }

    public void buyStock(PositionEntry position){
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Entity positionEntity = convertPositionEntryToEntity(position);
        TransactionEntry transactionEntry = new TransactionEntry();
        transactionEntry.setDate(position.getDate());
        transactionEntry.setAction("BUY");
        transactionEntry.setOwner(position.getOwner());
        transactionEntry.setPrice(position.getPurchasedPrice());
        transactionEntry.setSymbol(position.getSymbol());
        transactionEntry.setVolume(position.getVolume());
        Entity transactionEntity = convertTransactionEntryToEntity(transactionEntry);
        datastore.put(transactionEntity);
        positionEntity.setProperty("transactionId", transactionEntity.getKey().getId());
        position.setTransactionId(transactionEntity.getKey().getId());
        datastore.put(positionEntity);

    }


    public List<PositionTodayEntry> getPositionList(String owner) {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Query.Filter ownerFilter =
                new Query.FilterPredicate("owner",
                        Query.FilterOperator.EQUAL,
                        owner);
        Query query = new Query("Position")
                .addSort("date", Query.SortDirection.ASCENDING);
        query.setFilter(ownerFilter);
        List<Entity> entities = datastore.prepare(query).asList(FetchOptions.Builder.withDefaults());
        List<PositionTodayEntry> positionList = new ArrayList<PositionTodayEntry>();
        Map<String, StockTradeDailyEntry> priceMap = getCachedPrice();
        for(Entity entity: entities){
            PositionEntry position = convertEntityToPositionEntry(entity);
            PositionTodayEntry positionTodayEntry = PositionTodayEntry.calculatePositionToday(position, priceMap);
            positionList.add(positionTodayEntry);

        }

        return positionList;
    }

    public PositionEntry getPosition(long id) {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Key positionKey = KeyFactory.createKey("Position", id);

        Query query = new Query(positionKey);
        Entity entity = datastore.prepare(query).asSingleEntity();

        PositionEntry position = convertEntityToPositionEntry(entity);


        return position;
    }
    public TransactionEntry getTransaction(long id) {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Key positionKey = KeyFactory.createKey("Transaction", id);

        Query query = new Query(positionKey);
        Entity entity = datastore.prepare(query).asSingleEntity();

        TransactionEntry transactionEntry = convertEntityToTransactionEntry(entity);


        return transactionEntry;
    }

    public void deleteTransaction(TransactionEntry entry){
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Key transactionKey = KeyFactory.createKey("Transaction", entry.getId());

        datastore.delete(transactionKey);

    }

    public void updatePosition(PositionEntry positionEntry){
        Key positionKey =  KeyFactory.createKey("Position", positionEntry.getId());
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Query query = new Query(positionKey);
        Entity originalPositionEntity = datastore.prepare(query).asSingleEntity();
        originalPositionEntity.setProperty("symbol", positionEntry.getSymbol());
        originalPositionEntity.setProperty("date", positionEntry.getDate());
        originalPositionEntity.setProperty("owner", positionEntry.getOwner());
        originalPositionEntity.setProperty("price", convertValue(positionEntry.getPurchasedPrice()));
        originalPositionEntity.setProperty("volume", convertValue(positionEntry.getVolume()));

        datastore.put(originalPositionEntity);


    }

    public void addTransaction(TransactionEntry transactionEntry){
        //Entity entity = new Entity("Transaction");
        Entity entity = convertTransactionEntryToEntity(transactionEntry);
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        datastore.put(entity);

    }

    /*
    public void updatePosition(PositionEntry positionEntry) {

        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Key positionKey =  KeyFactory.createKey("Position", positionEntry.getId());
        Query query = new Query(positionKey);
        Entity newPositionEntity = convertPositionEntryToEntity(positionEntry);
        Entity originalPositionEntity = datastore.prepare(query).asSingleEntity();

        PositionEntry originalPositionEntry = convertEntityToPositionEntry(originalPositionEntity);
        PositionEntry newPositionEntry = convertEntityToPositionEntry(newPositionEntity);
        if (positionEntry.getTransactionId()!=0){
            Key transactionKey = KeyFactory.createKey("Transaction", positionEntry.getTransactionId());

            query = new Query(transactionKey);
            Entity transactionEntity = datastore.prepare(query).asSingleEntity();
            TransactionEntry transactionEntry = convertEntityToTransactionEntry(transactionEntity);
            if (transactionEntry.getVolume().equals(originalPositionEntry.getVolume())){
                transactionEntity.setProperty("symbol", positionEntry.getSymbol());
                transactionEntity.setProperty("date", positionEntry.getDate());
                transactionEntity.setProperty("owner", positionEntry.getOwner());
                transactionEntity.setProperty("price", convertValue(positionEntry.getPurchasedPrice()));
                transactionEntity.setProperty("volume", convertValue(positionEntry.getVolume()));
                datastore.put(transactionEntity);
            }
        }

        originalPositionEntity.setProperty("symbol", positionEntry.getSymbol());
        originalPositionEntity.setProperty("date", positionEntry.getDate());
        originalPositionEntity.setProperty("owner", positionEntry.getOwner());
        originalPositionEntity.setProperty("price", convertValue(positionEntry.getPurchasedPrice()));
        originalPositionEntity.setProperty("volume", convertValue(positionEntry.getVolume()));

        datastore.put(originalPositionEntity);

    }
    public void deletePosition(PositionEntry positionEntry){

        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

        Key positionKey =  KeyFactory.createKey("Position", positionEntry.getId());
        if (positionEntry.getTransactionId()!=0){
            Key transactionKey = KeyFactory.createKey("Transaction", positionEntry.getTransactionId());
            datastore.delete(positionKey, transactionKey);
        }else{
            datastore.delete(positionKey);
        }

    }
    */
    public Map<String, StockTradeDailyEntry> getCachedPrice(){
        MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
        syncCache.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));


        return (Map<String, StockTradeDailyEntry>)syncCache.get("price");
    }

    public void setPriceCache(List<StockTradeDailyEntry> list){
        MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();
        syncCache.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
        Map<String, StockTradeDailyEntry> map = new LinkedHashMap<String, StockTradeDailyEntry>();


        for(StockTradeDailyEntry entry: list){
            map.put(entry.getSymbol(), entry);

        }

        syncCache.put("price", map);
    }

}
